package com.example.demo.aspect;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.example.demo.annotation.Log;
import com.example.demo.entity.OperLog;
import com.example.demo.exception.CustomException;
import com.example.demo.service.LogService;
import com.example.demo.util.AuthContextUtil;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpMethod;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Date;
import java.util.Set;

/**
 * @description：日志切面类.
 * @author：lw
 * @create_time：2024/1/18
 **/


@Aspect
@Component
@Slf4j
public class LogAspect {            // 环绕通知切面类定义

    @Autowired
    private LogService logService;

    @Around(value = "@annotation(sysLog)")
    public Object doAroundAdvice(ProceedingJoinPoint joinPoint , Log sysLog) {

        OperLog sysOperLog = new OperLog() ;
        beforeHandleLog(sysLog , joinPoint , sysOperLog) ;  // 构建前置参数

        Object proceed = null;
        try {
            proceed = joinPoint.proceed(); // 执行方法
            afterHandlLog(sysLog , proceed , sysOperLog , 1 , null) ;  // 构建响应结果参数
        } catch (Throwable e) {
            //e.printStackTrace();                                // 打印异常信息
            afterHandlLog(sysLog , proceed , sysOperLog , 0 , e.getMessage()) ;
            logService.save(sysOperLog);
            JSONObject jsonObjectE=isCustomException(e);
            if(jsonObjectE!=null) { // 如果是自定义异常
                throw new CustomException(jsonObjectE.getInteger("code"),jsonObjectE.getString("message"));
            }
            else throw new RuntimeException(e.getMessage());
        }

        // 保存日志数据
        logService.save(sysOperLog);

        // 返回执行结果
        return proceed ;
    }

    private  JSONObject isCustomException(Object e){
        JSONObject jsonObjectE= JSON.parseObject(JSON.toJSONString(e));
        Set<String> eKeys=jsonObjectE.keySet();
        if(e.toString().startsWith(CustomException.class.getSimpleName()) && eKeys.contains("code") && eKeys.contains("message")) return jsonObjectE;
        return  null;
    }

    //操作执行之后调用
    private void afterHandlLog(Log sysLog, Object proceed,
                                     OperLog sysOperLog, int status ,
                                     String errorMsg) {
        if(sysLog.isSaveResponseData()) {
            sysOperLog.setJsonResult(JSON.toJSONString(proceed));
            sysOperLog.setOperTime(new Date());
        }
        sysOperLog.setStatus(status);
        sysOperLog.setErrorMsg(errorMsg);
    }

    //操作执行之前调用
    private void beforeHandleLog(Log sysLog,
                                       ProceedingJoinPoint joinPoint,
                                       OperLog sysOperLog) {

        // 设置操作模块名称
        sysOperLog.setTitle(sysLog.title());
        sysOperLog.setOperatorType(sysLog.operatorType().name());

        sysOperLog.setBusinessType(sysLog.businessType().name());

        // 获取目标方法信息
        MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature() ;
        Method method = methodSignature.getMethod();
        sysOperLog.setMethod(method.getDeclaringClass().getName());

        // 获取请求相关参数
        ServletRequestAttributes requestAttributes = (ServletRequestAttributes)
                RequestContextHolder.getRequestAttributes();
        assert requestAttributes != null;
        HttpServletRequest request = requestAttributes.getRequest();
        sysOperLog.setRequestMethod(request.getMethod());
        sysOperLog.setOperUrl(request.getRequestURI());
        sysOperLog.setOperIp(request.getRemoteAddr());

        // 设置请求参数
        if(sysLog.isSaveRequestData()) {
            String requestMethod = sysOperLog.getRequestMethod();
            if (HttpMethod.PUT.name().equals(requestMethod) || HttpMethod.POST.name().equals(requestMethod)) {
                String params = Arrays.toString(joinPoint.getArgs());
                sysOperLog.setOperParam(params);
            }
        }
        sysOperLog.setOperName(AuthContextUtil.get().getUsername());
    }
}







